#pragma once
#include "lockGuard.hpp"
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

const static int CAPACITY = 10;

template <class T>
class RingQueue
{
public:
    RingQueue(int num = CAPACITY)
        : _ring(num), _capacity(num), _consumeIndex(0), _produceIndex(0)
    {
        sem_init(&_spaceSem, 0, num);
        sem_init(&_dataSem, 0, 0);
        pthread_mutex_init(&_consumeMutex, nullptr);
        pthread_mutex_init(&_produceMutex, nullptr);
    }
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);
        pthread_mutex_destroy(&_consumeMutex);
        pthread_mutex_destroy(&_produceMutex);
    }

public:
    bool push(const T &task) // 生产者
    {
        P(&_spaceSem);
        {
            lockGuard lock(&_produceMutex); // 保护生产者索引
            _ring[_produceIndex] = task; // 生产者索引指向的位置放入数据
            _produceIndex = (_produceIndex + 1) % _capacity; // 生产者索引向后移动
        }
        V(&_dataSem); 
        return true;
    }

    bool pop(T* task) // 消费者
    {
        P(&_dataSem);
        {
            lockGuard lock(&_consumeMutex); // 保护消费者索引
            *task = _ring[_consumeIndex];
            _consumeIndex = (_consumeIndex + 1) % _capacity;
        }
        V(&_spaceSem);
        return true;
    }

private:
    void P(sem_t *sem) 
    {
        sem_wait(sem);
    }
    void V(sem_t *sem)
    {
        sem_post(sem);
    }

private:
    std::vector<T> _ring; // 环形队列
    int _capacity; // 队列容量
    sem_t _spaceSem; // 空闲空间计数
    sem_t _dataSem; // 数据空间计数
    int _consumeIndex; // 消费者索引
    int _produceIndex; // 生产者索引
    pthread_mutex_t _consumeMutex; // 消费者互斥锁
    pthread_mutex_t _produceMutex; // 生产者互斥锁
};